package com.netease.rtcdemo;


import static com.netease.lava.nertc.sdk.NERtcConstants.MediaCodecMode.MEDIA_CODEC_HARDWARE;
import static com.netease.lava.nertc.sdk.NERtcConstants.MediaCodecMode.MEDIA_CODEC_SOFTWARE;
import static com.netease.rtcdemo.GlobalRef.firstchat;

import android.Manifest;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.res.AssetManager;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.Looper;
import android.preference.PreferenceManager;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.text.TextUtils;
import android.util.Log;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ProgressBar;
import android.widget.Toast;

import com.netease.lava.base.http.HttpStack;
import com.netease.lava.base.http.HttpStackResponse;
import com.netease.lava.nertc.sdk.NERtcConstants;
import com.netease.lava.nertc.sdk.NERtcEx;
import com.netease.lava.nertc.sdk.NERtcOption;
import com.netease.lava.nertc.sdk.NERtcParameters;
import com.netease.lava.nertc.sdk.NERtcServerAddresses;
import com.netease.lava.nertc.sdk.audio.NERtcAudioRecordingConfiguration;
import com.netease.lava.nertc.sdk.stats.NERtcAudioRecvStats;
import com.netease.lava.nertc.sdk.stats.NERtcAudioSendStats;
import com.netease.lava.nertc.sdk.stats.NERtcVideoRecvStats;
import com.netease.lava.nertc.sdk.stats.NERtcVideoSendStats;
import com.netease.lava.nertc.sdk.video.NERtcBeautyEffectType;
import com.netease.lava.nertc.sdk.video.NERtcEncodeConfig;
import com.netease.lava.nertc.sdk.video.NERtcVideoConfig;
import com.netease.rtcdemo.screen.ScreenCaptureService;


import org.json.JSONException;
import org.json.JSONObject;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.nio.channels.NetworkChannel;
import java.util.Random;

public class MainActivity extends AppCompatActivity implements callbackDelegate {

    private static final boolean DEBUG = true;
    String APP_KEY = "";
    String HIGH_LOSS_APP_KEY = "2afbdfa4fe2f6";
    private static final String TAG = "cameraDemo";
    private Button mEnterRoom;
    private ImageView setting;
    private ImageView statistics;
    private String roomid;
    private long userId;
    private SharedPreferences mPreferences;
    private Handler uiHander = new Handler(Looper.getMainLooper());
    private int type = 1;
    private String roomServer = "";
    private NERtcVideoConfig.NERtcDegradationPreference mSubVideoDegradation = NERtcVideoConfig.NERtcDegradationPreference.DEGRADATION_DEFAULT;

    StatsHelper helper = StatsHelper.getInstance();
    private boolean mEnableBeauty;
    private LinearLayout progressBar;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initViews();
        ScreenCaptureService.getInstance().initContext(this);
        ScreenCaptureService.getInstance().bindScreenService();
        if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED ||
                ContextCompat.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED) {
            ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.RECORD_AUDIO}, 10008);
        }
        helper.setContext(this);
        copyAsset(getAssets(),"img.png", "/storage/emulated/0/Pictures/img.png", true);
    }
    @Override
    protected void onResume(){
        super.onResume();
        firstchat = false;
        NERtcEx.getInstance().release();
    }
    @Override
    protected void onDestroy() {
        super.onDestroy();
        NERtcCallback.getInstance().removeDelegate();
        try {
            ScreenCaptureService.getInstance().unbindScreenService();
        }catch (Exception e){

        }
    }
    public void launch(int type) {
        roomid = ((EditText)findViewById(R.id.roomId)).getText().toString();
        if(roomid.isEmpty()){
            Toast.makeText(this, "请输入房间号", Toast.LENGTH_SHORT).show();
            return;
        }
        String uid = ((EditText)findViewById(R.id.userId)).getText().toString();
        if(uid.isEmpty()){
            Toast.makeText(this, "请输入用户ID", Toast.LENGTH_SHORT).show();
            return;
        }
        if(!uid.isEmpty())
            userId = Integer.parseInt(uid);
        else{
            userId = 0;
        }
        mPreferences.edit().putLong("key_userid", userId).apply();

        beforeJoin();
        boolean autoEnableVideo = mPreferences.getBoolean(getString(R.string.setting_enable_local_video_auto), true);
        if(autoEnableVideo)
            NERtcEx.getInstance().enableLocalVideo(true);
        else
            NERtcEx.getInstance().enableLocalVideo(false);
        NERtcEx.getInstance().enableLocalAudio(true);
        if(roomServer != null){
            getDemoToken(String.valueOf(userId), token -> {
                int ret = NERtcEx.getInstance().joinChannel(token, roomid, userId);
            });
        }else {
            int ret = NERtcEx.getInstance().joinChannel(null, roomid, userId);
        }
        progressBar.setVisibility(View.VISIBLE);
        if(mEnableBeauty){
            NERtcEx.getInstance().enableBeauty(true);
            NERtcEx.getInstance().setBeautyEffect(NERtcBeautyEffectType.kNERtcBeautyWhiten, 1);
            NERtcEx.getInstance().setBeautyEffect(NERtcBeautyEffectType.kNERtcBeautySmooth, 1);
            NERtcEx.getInstance().setBeautyEffect(NERtcBeautyEffectType.kNERtcBeautySmallFace, 0.2f);
        }
    }

    private void beforeJoin() {
        mPreferences = PreferenceManager.getDefaultSharedPreferences(this);
        String privateParam = mPreferences.getString(getString(R.string.private_setting),"");
        boolean privateParamEnable = mPreferences.getBoolean(getString(R.string.private_setting_enable),false);
        NERtcServerAddresses mPrivateServer;
        NERtcOption option = new NERtcOption();
        if (privateParam != null && !privateParam.equals("") && privateParamEnable) {
            JSONObject jsonObject = null;
            try {
                jsonObject = new JSONObject(privateParam);
            } catch (JSONException e) {
                throw new RuntimeException(e);
            }
            mPrivateServer = new NERtcServerAddresses();
            roomServer = jsonObject.optString("demoServer");
            mPrivateServer.channelServer = jsonObject.optString("channelServer");
            Log.d(TAG,"channelServer：" + mPrivateServer.channelServer);
            mPrivateServer.statisticsServer = jsonObject.optString("statisticsServer");
            Log.d(TAG,"statisticsServer：" + mPrivateServer.statisticsServer);
            mPrivateServer.roomServer = jsonObject.optString("roomServer");
            Log.d(TAG,"roomServer：" + mPrivateServer.roomServer);
            mPrivateServer.compatServer = jsonObject.optString("compatServer");
            Log.d(TAG,"compatServer：" + mPrivateServer.compatServer);
            mPrivateServer.nosLbsServer = jsonObject.optString("nosLbsServer");
            Log.d(TAG,"nosLbsServer：" + mPrivateServer.nosLbsServer);
            mPrivateServer.nosUploadSever = jsonObject.optString("nosUploadSever");
            Log.d(TAG,"nosUploadSever：" + mPrivateServer.nosUploadSever);
            mPrivateServer.nosTokenServer = jsonObject.optString("nosTokenServer");
            Log.d(TAG,"nosTokenServer：" + mPrivateServer.nosTokenServer);
            mPrivateServer.cloudProxyServer = jsonObject.optString("cloudProxyServer");
            Log.d(TAG,"cloudProxyServer：" + mPrivateServer.cloudProxyServer);
            mPrivateServer.webSocketProxyServer = jsonObject.optString("webSocketProxyServer");
            Log.d(TAG,"webSocketProxyServer：" + mPrivateServer.webSocketProxyServer);
            mPrivateServer.quicProxyServer = jsonObject.optString("quicProxyServer");
            Log.d(TAG,"quicProxyServer：" + mPrivateServer.quicProxyServer);
            mPrivateServer.mediaProxyServer = jsonObject.optString("mediaProxyServer");
            Log.d(TAG,"mediaProxyServer：" + mPrivateServer.mediaProxyServer);
            mPrivateServer.statisticsDispatchServer = jsonObject.optString("statisticsDispatchServer");
            Log.d(TAG,"statisticsDispatchServer：" + mPrivateServer.statisticsDispatchServer);
            mPrivateServer.statisticsBackupServer = jsonObject.optString("statisticsBackupServer");
            Log.d(TAG,"statisticsBackupServer：" + mPrivateServer.statisticsBackupServer);
            mPrivateServer.useIPv6 = jsonObject.optBoolean("useIPv6", false);
            Log.d(TAG,"useIPv6：" + mPrivateServer.useIPv6);
            String priAppkey = jsonObject.optString("appkey");
            Log.d(TAG,"priAppkey：" + priAppkey);
            if (!TextUtils.isEmpty(priAppkey)) {
                APP_KEY = priAppkey;
            }
            option.serverAddresses = mPrivateServer;
        }

        boolean simulcastState = mPreferences.getBoolean(getString(R.string.setting_simulcast_enable), false);
        mEnableBeauty = mPreferences.getBoolean(getString(R.string.setting_enable_beauty), false);
        boolean aiStreamState = mPreferences.getBoolean(getString(R.string.setting_video_definition_enable), false);
        boolean nevcState = mPreferences.getBoolean(getString(R.string.setting_nevc_enable), false);
        boolean svcState = mPreferences.getBoolean(getString(R.string.setting_svc_enable), false);
        boolean h265Enable = false; // 因为 265 码表问题，暂时不可以用于演示
        //boolean h265Enable = mPreferences.getBoolean(getString(R.string.setting_enable_h265), false);
        boolean hardWareState = mPreferences.getBoolean(getString(R.string.setting_hardware_code_enable), false);
        int Resolution = Integer.parseInt(mPreferences.getString(getString(R.string.setting_video_resolution), "3"));
        int FrameRate = Integer.parseInt(mPreferences.getString(getString(R.string.setting_video_framerate), "3"));
        int audioProfile = Integer.parseInt(mPreferences.getString(getString(R.string.setting_audio_profile), "0"));
        int scenario = Integer.parseInt(mPreferences.getString(getString(R.string.setting_audio_scenario), "0"));
        int videoPrefer =  Integer.parseInt(mPreferences.getString(getString(R.string.setting_video_profile), "0"));
        switch (videoPrefer) {
            case 0:
                mSubVideoDegradation = NERtcVideoConfig.NERtcDegradationPreference.DEGRADATION_DEFAULT;
                break;
            case 1:
                mSubVideoDegradation = NERtcVideoConfig.NERtcDegradationPreference.DEGRADATION_MAINTAIN_FRAMERATE;
                break;
            case 2:
                mSubVideoDegradation = NERtcVideoConfig.NERtcDegradationPreference.DEGRADATION_MAINTAIN_QUALITY;
                break;
            case 3:
                mSubVideoDegradation = NERtcVideoConfig.NERtcDegradationPreference.DEGRADATION_BALANCED;
                break;
            default:
                break;
        }

        Log.d(TAG,"接收参数2:" + "私有化参数" + privateParam + ", simulcastState:" + simulcastState + ", 智码:" + aiStreamState +
                ", nevc:" + nevcState  + ", 硬编:" + hardWareState + ", 帧率:" + FrameRate +
                ", 分辨率:" + Resolution );
        setupNERtc(option, aiStreamState, nevcState, hardWareState, svcState, h265Enable);
        NERtcEx.getInstance().setStatsObserver(helper);
        NERtcEx.getInstance().enableDualStreamMode(simulcastState);
        NERtcEx.getInstance().setAudioProfile(audioProfile, scenario);
        setlocalVideoConfig(FrameRate, Resolution);
        int channelprofile = Integer.parseInt(mPreferences.getString(getString(R.string.setting_channel_profile), "0"));
        if(channelprofile == 0){
            NERtcEx.getInstance().setChannelProfile(NERtcConstants.RTCChannelProfile.COMMUNICATION);
        }else{
            NERtcEx.getInstance().setChannelProfile(NERtcConstants.RTCChannelProfile.LIVE_BROADCASTING);
        }

        int joinMaxTimeOut = Integer.parseInt(mPreferences.getString(getString(R.string.setting_join_max_time_out), "0"));
        if (joinMaxTimeOut > 0) {
            NERtcParameters parameters = new NERtcParameters();
            NERtcParameters.Key max_time_out= NERtcParameters.Key.createSpecializedKey("sdk.join.max.time.out");
            parameters.set(max_time_out, joinMaxTimeOut);
            NERtcEx.getInstance().setParameters(parameters);
        }
    }

    private void setlocalVideoConfig(int frameRate, int videoProfile) {
        NERtcVideoConfig config = new NERtcVideoConfig();

        config.frameRate = NERtcEncodeConfig.NERtcVideoFrameRate.values()[frameRate + 1];
        config.videoProfile = videoProfile + 1;
        config.degradationPrefer = mSubVideoDegradation;
        NERtcEx.getInstance().setLocalVideoConfig(config);
    }

    private void setupNERtc(NERtcOption options, boolean aiStream, boolean nevc, boolean hardWareState, boolean svcState, boolean h265Enable) {
        NERtcParameters parameters = new NERtcParameters();
        if(aiStream){
            NERtcParameters.Key video4k = NERtcParameters.Key.createSpecializedKey("engine.video.enable_jnd");
            parameters.set(video4k, true);
        }else{
            NERtcParameters.Key video4k = NERtcParameters.Key.createSpecializedKey("engine.video.enable_jnd");
            parameters.set(video4k, false);
        }
        parameters.set(NERtcParameters.KEY_VIDEO_SEND_MODE, 0);

        if(svcState) {
            NERtcParameters.Key svc = NERtcParameters.Key.createSpecializedKey("engine.video.enable_svc");
            parameters.set(svc, true);
        }else {
            NERtcParameters.Key svc = NERtcParameters.Key.createSpecializedKey("engine.video.enable_svc");
            parameters.set(svc, false);
        }
        if(nevc) {
            NERtcParameters.Key based_264 = NERtcParameters.Key.createSpecializedKey("engine.video.enable_nevc2_based_264");
            parameters.set(based_264, true);
            NERtcParameters.Key enc = NERtcParameters.Key.createSpecializedKey("engine.video.enable_nevc2_enc");
            parameters.set(enc, true);
            NERtcParameters.Key dec = NERtcParameters.Key.createSpecializedKey("engine.video.enable_nevc2_dec");
            parameters.set(dec, true);
            NERtcParameters.Key superres = NERtcParameters.Key.createSpecializedKey("engine.video.enable_nevc_adaptive_superres");
            parameters.set(superres, true);
        }else {
            NERtcParameters.Key based_264 = NERtcParameters.Key.createSpecializedKey("engine.video.enable_nevc2_based_264");
            parameters.set(based_264, false);
            NERtcParameters.Key enc = NERtcParameters.Key.createSpecializedKey("engine.video.enable_nevc2_enc");
            parameters.set(enc, false);
            NERtcParameters.Key dec = NERtcParameters.Key.createSpecializedKey("engine.video.enable_nevc2_dec");
            parameters.set(dec, false);
            NERtcParameters.Key superres = NERtcParameters.Key.createSpecializedKey("engine.video.enable_nevc_adaptive_superres");
            parameters.set(superres, false);
        }
        NERtcParameters.Key enableDevEnvPram = NERtcParameters.Key.createSpecializedKey("key_test_server_uri");
        parameters.set(enableDevEnvPram, true);
        if(hardWareState){
            parameters.set(NERtcParameters.KEY_VIDEO_ENCODE_MODE, MEDIA_CODEC_HARDWARE);
        }else {
            parameters.set(NERtcParameters.KEY_VIDEO_ENCODE_MODE, MEDIA_CODEC_SOFTWARE);
        }


        NERtcParameters.Key h265 = NERtcParameters.Key.createSpecializedKey("key_h265_switch");
        parameters.set(h265, false);

        boolean serverRecordHost = mPreferences.getBoolean(getString(R.string.setting_server_record_host_key), false);
        parameters.set(NERtcParameters.KEY_SERVER_RECORD_SPEAKER, serverRecordHost);
        if(serverRecordHost) {
            parameters.set(NERtcParameters.KEY_SERVER_RECORD_AUDIO, true);
            parameters.set(NERtcParameters.KEY_SERVER_RECORD_VIDEO, true);
            parameters.set(NERtcParameters.KEY_SERVER_RECORD_MODE, 0);
        }

        Boolean highLossTest = mPreferences.getBoolean(getString(R.string.setting_high_loss_enable), false);
        if (highLossTest) {
            NERtcParameters.Key extreme_loss_opt = NERtcParameters.Key.createSpecializedKey("engine.qos.extreme_loss_opt");
            parameters.set(extreme_loss_opt, true);
            NERtcParameters.Key cc_video_bitrate_verify = NERtcParameters.Key.createSpecializedKey("engine.qos.cc_video_bitrate_verify");
            parameters.set(cc_video_bitrate_verify, "{\"enable\":true, \"fast_drop\":false}");
            NERtcParameters.Key turn_on_lossbased_gcc_optimize = NERtcParameters.Key.createSpecializedKey("turn_on_lossbased_gcc_optimize");
            parameters.set(turn_on_lossbased_gcc_optimize, false);
        }
        
        NERtcEx.getInstance().setParameters(parameters);

//        if (BuildConfig.DEBUG) {
            options.logLevel = NERtcConstants.LogLevel.INFO;
//        } else {
//            options.logLevel = NERtcConstants.LogLevel.WARNING;
//        }
        String appkey = highLossTest ? HIGH_LOSS_APP_KEY : APP_KEY;

        try {
            Log.d(TAG, "APP_KEY:" + appkey);
            NERtcEx.getInstance().init(getApplicationContext(), appkey, NERtcCallback.getInstance(), options);
        } catch (Exception e) {

        }

        if(mEnableBeauty){
            NERtcEx.getInstance().startBeauty();
        }

    }
    public void launchSetting() {
        startActivity(new Intent(MainActivity.this, SettingsUI.class));
    }
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
    }
    @SuppressLint("ClickableViewAccessibility")
    private void initViews() {
        mEnterRoom = findViewById(R.id.enter_room);
        setting = findViewById(R.id.setting);
        setting.setOnClickListener(v -> launchSetting());
        progressBar = findViewById(R.id.progress_bar);
        mPreferences = PreferenceManager.getDefaultSharedPreferences(this);
        long savedUid = mPreferences.getLong("key_userid", 0);
        if (savedUid == 0) { // 还没有值
            Random random = new Random();
            savedUid = 10000 + random.nextInt(90000); // 随机一个五位数
        }
        EditText editTextUserId = findViewById(R.id.userId);
        editTextUserId.setText(String.valueOf(savedUid));

        statistics = findViewById(R.id.statistics);
        statistics.setOnClickListener(v -> {
            Intent intent = new Intent();
            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            intent.setClass(MainActivity.this, WebViewActivity.class);
            startActivity(intent);
        });

        mEnterRoom.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                launch(type);
            }
        });

        NERtcCallback.getInstance().registerDelegate(this);
    }
    @Override
    protected void onStart() {
        if (DEBUG) Log.d(TAG, "onStart:");
        super.onStart();

    }

    @Override
    protected void onStop() {
        if (DEBUG) Log.d(TAG, "onStop:");
        super.onStop();
    }


    @Override
    public void onJoinChannel(int result, long channelId, long elapsed, long uid) {
        Log.d(TAG, "onJoinChannel: result:" + result);
        if(result == 0) {
            Intent intent = new Intent();
            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            intent.setClass(this, multiChatActivity.class);
            intent.putExtra(multiChatActivity.ROOM_NAME_TAG, roomid);
            intent.putExtra(multiChatActivity.ROOM_CID_TAG, channelId);
            startActivity(intent);
        }else {
            Toast.makeText(this, "加入房间失败 code:" + result, Toast.LENGTH_SHORT).show();
        }
        NERtcEx.getInstance().startAudioDump();
        progressBar.setVisibility(View.INVISIBLE);
    }

    @Override
    public void onDisconnect(int reason) {

    }

    @Override
    public void onUserJoined(long uid) {

    }

    @Override
    public void onUserLeave(long uid, int reason) {

    }

    @Override
    public void onUserVideoStart(long uid, int maxProfile) {
        if (GlobalRef.chatUiRef == null) {
            uiHander.postDelayed(new Runnable() {
                @Override
                public void run() {
                    if (GlobalRef.chatUiRef == null) {
                        uiHander.postDelayed(this, 200);
                    } else {
                        try {
                            Object instance = GlobalRef.chatUiRef.get();
                            Field field = multiChatActivity.class.getDeclaredField("mRemoteUserMap");
                            field.setAccessible(true);

                            Method method = multiChatActivity.class.getDeclaredMethod("createRemoteUserRender", long.class, boolean.class, boolean.class);
                            method.setAccessible(true);
                            method.invoke(instance, uid, false, true);
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                }
            }, 200);
        }
    }

    @Override
    public void onUserVideoStop(long uid) {

    }

    @Override
    public void onUserSubStreamVideoStart(long uid, int maxProfile) {
        if (GlobalRef.chatUiRef == null) {
            uiHander.postDelayed(new Runnable() {
                @Override
                public void run() {
                    if (GlobalRef.chatUiRef == null) {
                        uiHander.postDelayed(this, 100);
                    } else {
                        try {
                            Object instance = GlobalRef.chatUiRef.get();
                            Field field = multiChatActivity.class.getDeclaredField("mRemoteUserMap");
                            field.setAccessible(true);

                            Method method = multiChatActivity.class.getDeclaredMethod("createRemoteUserRender", long.class, boolean.class,boolean.class);
                            method.setAccessible(true);
                            method.invoke(instance, uid, false, false);
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                }
            }, 100);
        }
    }

    @Override
    public void onUserSubStreamVideoStop(long uid) {

    }

    @Override
    public void onLocalVideoStats(NERtcVideoSendStats stats) {

    }

    @Override
    public void onRemoteVideoStats(NERtcVideoRecvStats[] statsArray) {

    }

    @Override
    public void onLocalAudioStats(NERtcAudioSendStats stats) {

    }

    @Override
    public void onRemoteAudioStats(NERtcAudioRecvStats[] statsArray) {

    }

    public static int copyAsset(AssetManager manager, String src, String dest, boolean overwrite) {
        if (manager == null) {
            Log.e(TAG, "AssetManager is null");
            return -1;
        }

        File outfile = new File(dest);
        if (outfile.isDirectory()) {
            Log.e(TAG, "copyAsset failed, " + dest + " is a director, use copyAssetRecursive");
            return -1;
        }

        if (!overwrite && outfile.exists()) {
            Log.i(TAG, dest + " is exist, and not overwrite mode, skip");
            return 0;
        }

        InputStream input = null;
        OutputStream output = null;
        try {
            input = manager.open(src);
            output = new FileOutputStream(outfile);
            byte[] buf = new byte[1024];
            int read;
            while ((read = input.read(buf)) != -1) {
                output.write(buf, 0, read);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (input != null) {
                    input.close();
                }
                if (output != null) {
                    output.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        return 0;
    }
    public interface DemoTokenCallback {
        void onToken(String token);
    }
    public void getDemoToken(String uid, DemoTokenCallback callback) {
        new Thread(() -> {
            try {
                String queryString = roomServer + "?uid=" + uid + "&appkey=" + APP_KEY;
                HttpStackResponse response = HttpStack.doPost(queryString,null,null,5000);
                Log.i(TAG, "getDemoToken: " + queryString + " , res: " + response);
                if (response == null || response.code != 200 || TextUtils.isEmpty(new String(response.result))) {
                    callback.onToken(null);
                    return;
                }
                JSONObject object = new JSONObject(new String(response.result));
                int code = object.getInt("code");
                String token = object.getString("checksum");
                if (code != 200 || TextUtils.isEmpty(token)) {
                    callback.onToken(null);
                    return;
                }
                callback.onToken(token);
            } catch (Exception e) {
                e.printStackTrace();
                callback.onToken(null);
            }

        }).start();
    }
}